home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / USB DDK 1.4.6f4 / Examples / USBSampleStorageDriver / UnitTableDriver / UnitTableDriveQSupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-25  |  46.3 KB  |  1,634 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        UnitTableDriveQSupport.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 2000 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. /*
  13.     File:        UnitTableDriveQSupport.c
  14.  
  15.     Contains:    All functionality for managing Drive Queue elements. 
  16.  
  17.     Version:    1.0
  18.  
  19.     Copyright:    © 1998-2000 by Apple Computer, Inc., all rights reserved.
  20.  
  21.  
  22. */
  23. #include <DriverGestalt.h>
  24. #include <Gestalt.h>
  25. #include <Files.h>
  26. #include <LowMem.h>
  27. #include <SCSI.h>  // For Block 0 and some partition map definitions.
  28.  
  29. #include "UnitTableFunctions.h"
  30. #include "UnitTableFloppySupport.h"
  31. #include "UnitTableDriveQSupport.h"
  32. #include "UnitTableDeviceAccess.h"
  33. #include "UnitTableDriverIcons.h"
  34. #include "UnitTableReadWriteSupport.h"
  35.  
  36. // pmPartStatus field flags
  37. // Old versions from ATA and SCSI - should be deprecated
  38. // but need to be supported since they are used by Drive Setup.
  39. enum 
  40. {
  41.     kPMapDriveSetupSig    =    'DSU1',
  42.     STAT_WRITABLE        =    0x20,
  43.     STAT_MOUNT            =    0x40000000,
  44.     STAT_STARTUP        =    0x80000000
  45. };
  46.  
  47. // New fields that will definitely be added to SCSI.h (should add the AUX fields also)
  48. enum
  49. {
  50.     // Drive Setup doesn't play nicely with others or these values
  51. /*    kPartitionHFSIsWriteProtected    = 0x00000100,*/
  52. /*    kPartitionHFSDoNotAutomount        = 0x00000200,*/
  53. /*    kPartitionHFSIsStartup            = 0x00000400,    // This may not be needed for new drivers*/
  54. /**/
  55. /*    kPartitionHFSStatusBitsMask        = 0x0000FF00*/
  56.     kPartitionHFSIsWriteProtected    = 0x00010000,
  57.     kPartitionHFSDoNotAutomount        = 0x00020000,
  58.     kPartitionHFSIsStartup            = 0x00040000,    // This may not be needed for new drivers
  59.  
  60.     kPartitionHFSStatusBitsMask        = 0x00FF0000
  61. };
  62.  
  63. enum
  64. {
  65.     kInstallStartState = 1,
  66.     kInstallPartitionReadDoneState,
  67.     kInstallReadNextPartBlock,
  68.     kInstallProcessNextPartBlock
  69. };
  70.  
  71. typedef struct InstallPB
  72. {
  73.     volatile OSStatus                status;
  74.     void                             *ourCompletion;
  75.     UInt32                            capacity;
  76.     UInt32                            blockSize;
  77.     OSType                            currentMediaType;
  78.     UInt8                            currentState;
  79.     UInt32                            currentPartBlock;
  80.     UInt32                            lastPartBlock;
  81.     DriveInstallCompletionProcPtr    installCompletion;
  82.     Boolean                            useNativeBlocks;
  83.     UInt8                            buffer[2048];
  84. };
  85.  
  86. typedef    struct InstallPB    InstallPB, *InstallPBPtr;
  87.  
  88. #define kNumberOfDriveRecords    12
  89.  
  90. static InstallPB    theInstallPB;
  91. static DriveQRec    theDriveQRecArray[kNumberOfDriveRecords];
  92. static DriverRefNum    gOurDrvrRefNum;
  93. static TimerID        gPostEventTimer = 0;
  94. static UInt16        gCurrentDriverMode = kDriverModeNormal;
  95. static Boolean        gDoPostEvents = true;
  96.  
  97. static void         ResetDriveQueue( DriveQRecPtr drive);
  98. static DriveQRecPtr FindPermanentDriveQRec( void );
  99.  
  100. static DriveQRecPtr    CreateDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset );
  101.  
  102. static void         ScanMediaForPartitions( UInt32 userData, OSStatus status );
  103.  
  104. static Boolean         ShouldPartitionBeMounted( Partition* thePartition );
  105.  
  106. static void             EjectDrive(DriveQRecPtr theDrivePtr);
  107. static OSStatus        PostTheDiskInsertEvents( void );
  108. static OSStatus     RetryPostEventInterrupt( void *p1, void *p2);
  109.  
  110. // This may be removed
  111. static Boolean         IsVolumeMountedForDrive(UInt16 driveNum);
  112.  
  113. #pragma mark --
  114. #pragma mark Driver Mode routines
  115. static UInt32 gModeUserData;
  116. static UInt16 ReadOnlyMediaDriveNum = 0;
  117. static ControlStatusCompletionProcPtr gModeCompletionProc;
  118.  
  119. static void StartNormalModeCompletion(Boolean wasSuccessful);
  120.  
  121. OSStatus DriveQueueControlCallSupport(     UInt32                                    userData,
  122.                                         CntrlParamPtr                            cntrlPBPtr,
  123.                                         ControlStatusCompletionProcPtr            callBack )
  124. {
  125.     OSStatus        err        = noErr;
  126.     SInt16            driveNum;
  127.  
  128.     gModeUserData             = userData;
  129.     gModeCompletionProc     = callBack;
  130.  
  131.     driveNum = cntrlPBPtr->ioVRefNum;
  132.     
  133.     // Parse the control codes…
  134.     switch( cntrlPBPtr->csCode ) 
  135.     {
  136.         case kcsSetDriverMode:                        // Change the driver's operating mode
  137.         {
  138.             UInt16             newMode = cntrlPBPtr->csParam[0];
  139.             DriveQRecPtr    driveQPtr;
  140.             Boolean         volumeMounted = false;
  141.                                 
  142.             if ( newMode == gCurrentDriverMode )
  143.             {
  144.                 // The new mode is the same as the current mode, do nothing
  145.                 // and return noErr
  146.                 err = noErr;
  147.                 break;
  148.             }
  149.             
  150.             driveQPtr = GetFirstDriveQRec();
  151.             while ( driveQPtr != nil )
  152.             {
  153.                 // Check each drive owned by the driver for mounted volumes
  154.                 if ( IsVolumeMountedForDrive ( driveQPtr->driveNum ) == true )
  155.                 {
  156.                     // There are still volumes mounted for the drive, this prevents
  157.                     // the driver from changing modes.
  158.                     volumeMounted = true;
  159.                     break;
  160.                 }
  161.                 
  162.                 driveQPtr = GetNextDriveQRec( driveQPtr );
  163.             }
  164.     
  165.             if (volumeMounted == true )
  166.             {
  167.                 err = paramErr;
  168.                 break;
  169.             }
  170.  
  171.             if ( newMode == kDriverModeNormal )
  172.             {
  173.                 gCurrentDriverMode = newMode;
  174.                 if ( cntrlPBPtr->csParam[1] != 0 )
  175.                 {
  176.                     gDoPostEvents = false;
  177.                 }
  178.                 
  179.                 EjectDrive( FindPermanentDriveQRec());
  180.                  InstallDrive( &StartNormalModeCompletion );
  181.                 err = kRequestPending;
  182.             }
  183.             else if ( newMode == kDriverModeUtility )
  184.             {
  185.                 // Set mode to utility
  186.                 gCurrentDriverMode = newMode;
  187.  
  188.                 // Do an eject on all drive Q elements to remove from the queue
  189.                 driveQPtr = GetFirstDriveQRec();
  190.                 while ( driveQPtr != nil )
  191.                 {
  192.                     if ( driveQPtr != FindPermanentDriveQRec())
  193.                     {
  194.                         EjectDrive( driveQPtr );
  195.                     }
  196.                     
  197.                     driveQPtr = GetNextDriveQRec( driveQPtr );
  198.                 }
  199.                 
  200.                 // Update the permanent to represent the entire media
  201.                 FindPermanentDriveQRec()->partoffset = FindPermanentDriveQRec()->curoffset = 0;
  202.                 UpdateQ(FindPermanentDriveQRec()->driveNum, FindPermanentDriveQRec()->capacity);
  203.                 err = noErr;
  204.             }
  205.             else
  206.             {
  207.                 err = paramErr;
  208.             }
  209.         }
  210.         break;
  211.  
  212.         case kcsManageReadOnlyMediaQueue:
  213.         {
  214.             UInt16             newMode = cntrlPBPtr->csParam[0];
  215.             DriveQRecPtr    driveQPtr;
  216.  
  217.             if ( newMode == kReadOnlyMediaQueueInstall )
  218.             {
  219.                 // Install a Write protected Drive queue element to represent the entire media
  220.                 // and return the DriveNum in csParam[1]
  221.                 if ( GetNumberOfVolumes() == 0 )
  222.                 {
  223.                     // There are no mounted volumes, and so probably no media in the\
  224.                     // drive.  Return a paramErr.
  225.                     err = paramErr;
  226.                     break;
  227.                 }
  228.                 
  229.                 driveQPtr = CreateNewDriveQRecForPartition( NextPartitionID(), 0, 0 );
  230.                 if ( driveQPtr ) 
  231.                 {
  232.                     driveQPtr->isWriteProtected = true;
  233.  
  234.                     UpdateQ(driveQPtr->driveNum, driveQPtr->capacity);
  235.                     ReadOnlyMediaDriveNum = cntrlPBPtr->csParam[1] = driveQPtr->driveNum;
  236.                     err = noErr;
  237.                 }
  238.                 else
  239.                 {
  240.                     err = controlErr;
  241.                 }
  242.             }
  243.             else if ( newMode == kReadOnlyMediaQueueRemove )
  244.             {
  245.                 // If there is a Read Only Media drive queue installed, remove it now
  246.                 
  247.                 // Make sure that the passed in drive does not have a mounted volume.
  248.                 if ( IsVolumeMountedForDrive ( ReadOnlyMediaDriveNum ) == true )
  249.                 {
  250.                     // There are still volumes mounted for the drive, this means that
  251.                     // this is not the Read Only queue.  Return paramErr.
  252.                     err = paramErr;
  253.                     break;
  254.                 }
  255.  
  256.                 driveQPtr = FindDriveQRecForDriveNum( ReadOnlyMediaDriveNum );
  257.                 if ( driveQPtr != nil )
  258.                 {
  259.                     RemoveDrive(driveQPtr);
  260.                     err = noErr;
  261.                 }
  262.                 else
  263.                 {
  264.                     err = paramErr;
  265.                 }
  266.                 
  267.                 ReadOnlyMediaDriveNum = 0;
  268.             }
  269.             else
  270.             {
  271.                 // The function passed in is not defined, return a paramErr.
  272.                 err = paramErr;
  273.             }
  274.         }
  275.         break;
  276.  
  277.         default:
  278.         {
  279.             err = controlErr;
  280.         }
  281.         break;
  282.     }
  283.     
  284.     return err;
  285. }
  286.  
  287. void StartNormalModeCompletion(Boolean wasSuccessful)
  288. {
  289.     OSStatus    err;
  290.     
  291.     gDoPostEvents = true;
  292.     if ( wasSuccessful == true )
  293.     {
  294.         err = noErr;
  295.     }
  296.     else
  297.     {
  298.         err = ioErr;
  299.     }
  300.  
  301.     (*gModeCompletionProc) (gModeUserData, err);
  302. }
  303.  
  304. OSStatus DriveQueueStatusCallSupport(     UInt32                            userData,
  305.                                         CntrlParamPtr                    cntrlPBPtr,
  306.                                         ControlStatusCompletionProcPtr    callBack )
  307. {
  308.     OSStatus        err    = noErr;
  309.     SInt16            driveNum;
  310.  
  311.     gModeUserData             = userData;
  312.     gModeCompletionProc     = callBack;
  313.  
  314.     driveNum = cntrlPBPtr->ioVRefNum;
  315.     
  316.     // Parse the control codes…
  317.     switch(cntrlPBPtr->csCode) 
  318.     {
  319.         case kcsGetDriverMode:
  320.         {
  321.             cntrlPBPtr->csParam[0] = gCurrentDriverMode;
  322.             if ( gCurrentDriverMode == kDriverModeUtility )
  323.             {
  324.                 // This is the get mode info call for Utility mode,
  325.                 // return the drive number representing the whole disk.
  326.                 cntrlPBPtr->csParam[1] = FindPermanentDriveQRec()->driveNum;
  327.             }
  328.             
  329.             err = noErr;
  330.         }
  331.         break;
  332.  
  333.         case kcsManageReadOnlyMediaQueue:
  334.         {
  335.             if ( ReadOnlyMediaDriveNum == 0 )
  336.             {
  337.                 err = paramErr;
  338.                 break;
  339.             }
  340.             
  341.             cntrlPBPtr->csParam[0] = ReadOnlyMediaDriveNum;            
  342.             err = noErr;
  343.         }
  344.         break;
  345.  
  346.         default:
  347.         {
  348.             err = statusErr;
  349.         }
  350.         break;
  351.     }
  352.     
  353.     return err;
  354. }
  355.  
  356.  
  357. #pragma mark --
  358. #pragma mark Drive Information Query Functions
  359. Boolean IsDriveNumberValid( UInt16 driveNum )
  360. {
  361.     DriveQRecPtr theDriveQRec;
  362.  
  363.     theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  364.     if ( theDriveQRec != nil )
  365.     {
  366.         return true;
  367.     }
  368.     
  369.     return false;
  370. }
  371.  
  372. Boolean IsDriveNumWriteProtected( UInt16 driveNum )
  373. {
  374.     DriveQRecPtr theDriveQRec;
  375.  
  376.     if( IsDriveAFloppy( driveNum ) == true )
  377.     {
  378.         theDriveQRec = GetFloppyDriveRec();
  379.     }
  380.     else
  381.     {
  382.         theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  383.     }
  384.     
  385.     if ( theDriveQRec != nil )
  386.     {
  387.         return theDriveQRec->isWriteProtected;
  388.     }
  389.     
  390.     return false;
  391. }
  392.  
  393. Boolean AreThereMountedDrives( void )
  394. {
  395.     int    loopCount;
  396.     
  397.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  398.     {
  399.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  400.         {
  401.             return true;
  402.         }
  403.     }
  404.     
  405.     return false;
  406. }
  407.  
  408. UInt32 GetNumberOfVolumes( void )
  409. {
  410.     int        loopCount;
  411.     UInt32    volCount = 0;
  412.     
  413.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  414.     {
  415.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  416.         {
  417.             volCount++;
  418.         }
  419.     }
  420.     
  421.     return volCount;
  422. }
  423.  
  424. OSType GetMediaTypeForDriveNum( UInt16 driveNum )
  425. {
  426.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  427.     
  428.     drive = FindDriveQRecForDriveNum( driveNum );
  429.     return drive->deviceType;
  430. }
  431.  
  432. void GetMediaIconForDriveNum( UInt16 driveNum, DiskIcon    *iconPtr )
  433. {
  434.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  435.     
  436.     drive = FindDriveQRecForDriveNum( driveNum );
  437.     BlockMoveData(drive->mediaIconPtr, iconPtr, sizeof(DiskIcon));
  438. }
  439.  
  440. void GetDriveStatusForDriveNum( UInt16 driveNum, DrvSts *statusPtr )
  441. {
  442.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  443.     
  444.     drive = FindDriveQRecForDriveNum( driveNum );
  445.     BlockMoveData(&drive->driveStatus, statusPtr, sizeof(DrvSts));
  446. }
  447.  
  448. #pragma mark --
  449. #pragma mark Drive Queue Management Functions
  450. // This is to workaround a bug in the PowerPC native version of the AddDrive
  451. // call in systems before 8.5, where one needs to be added to the desired
  452. // drive number before calling AddDrive.
  453. void NativeAddDrive(DriverRefNum drvrRefNum, UInt16 driveNumber, DrvQElPtr drvQEl)
  454. {
  455.     UInt32        gestaltResponse;
  456.     OSStatus    gestaltErr;
  457.  
  458.     // Check System version to see if we need to add one to AddDrive calls
  459.     gestaltErr = Gestalt(gestaltSystemVersion,(long *) &gestaltResponse);
  460.  
  461.     // If this is boot time, the system version will be reported as 0x0000.  
  462.     // If we are booting, we must be on a system greater than 8.5, so we do not need the fix
  463.     if( (gestaltErr == noErr) && (( (gestaltResponse&0xFFFF) < 0x0850 ) && ((gestaltResponse&0xFFFF) != 0x0000 )))
  464.     {
  465.         // We are on a system before 8.5, we need to add 1 to AddDrive calls
  466.         driveNumber += 1;
  467.     }
  468.  
  469.     AddDrive( drvrRefNum, driveNumber, drvQEl);
  470. }
  471.  
  472. void ResetDriveQueue( DriveQRecPtr drive)
  473. {
  474.     if(drive->isFloppy == true)
  475.     {
  476.         ResetFloppyDriveQueue( drive );
  477.     }
  478.     else
  479.     {
  480.         drive->driveStatus.track         = 0;            // Not used on non floppies
  481.         drive->driveStatus.writeProt     = 0;            // not write protected yet
  482.         drive->driveStatus.diskInPlace     = 0;            // Ejectable Disk
  483.         drive->driveStatus.installed     = 1;            // drive is installed
  484.         drive->driveStatus.sides         = 0;            // Not used on non floppy disks
  485.         drive->driveStatus.qType         = 1;            // both dQDrvSz and dQDrvSz2 are used
  486.         drive->driveStatus.dQFSID         = 0;            // File Manager's volume type
  487.         drive->driveStatus.driveSize    = 0;            // volume size in blocks
  488.         drive->driveStatus.driveS1         = 0;
  489.     }
  490. }
  491.  
  492. static Boolean    driveQueueIsInstalled = false;
  493.  
  494. OSStatus InstallDriveQueueElement( DriverRefNum theDrvrRefNum )
  495. {
  496.     OSStatus                                     err = noErr;
  497.     int                                            loopCount;
  498.     DriveQRecPtr                                theDriveQPtr = nil;
  499.     DriverGestaltSupportedMediaTypesResponse    *supportedTypes;
  500.     
  501.     gOurDrvrRefNum = theDrvrRefNum;
  502.     
  503.     if(IsDeviceAccessEnabled() == false )
  504.     {
  505.         return kDeviceAccessNotAvailable;
  506.     }
  507.  
  508.     if ( driveQueueIsInstalled == true )
  509.     {
  510.         return noErr;
  511.     }
  512.  
  513.     driveQueueIsInstalled = true;
  514.  
  515.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  516.     {
  517.         BlockZero( &theDriveQRecArray[loopCount], sizeof( DriveQRec ));
  518.         theDriveQRecArray[loopCount].isValidRecord = false;
  519.     }
  520.     
  521.     supportedTypes = GetSupportedMediaTypesPtr();
  522.     
  523.     for ( loopCount = 0; loopCount < supportedTypes->supportTypesCount; loopCount++)
  524.     {
  525.         if ( supportedTypes->supportedTypesArray[loopCount] == kdgFloppyType )
  526.         {
  527.             err = SetupFloppyStructures( theDrvrRefNum );
  528.         }
  529.         else
  530.         {
  531.             theDriveQPtr = GetNewDriveQRec();
  532.             ResetDriveQueue( theDriveQPtr );
  533.             theDriveQPtr->deviceType = supportedTypes->supportedTypesArray[loopCount];
  534.             theDriveQPtr->driveNum = NextQDrive();                    // assign a logical drive number
  535.             theDriveQPtr->isPermanentQElement = true;
  536.             NativeAddDrive(theDrvrRefNum, theDriveQPtr->driveNum,(DrvQElPtr)  &theDriveQPtr->driveStatus.qLink);
  537.         }
  538.     }
  539.     
  540.     if ( theDriveQPtr != nil )
  541.     {
  542.         // Wait until after the floppy queue is added to clear this field
  543.         // This prevents floppy from getting the same drive queue element on devices
  544.         // that support both floppy and non-floppy removables
  545.         theDriveQPtr->isValidRecord = false;
  546.     }
  547.  
  548.     return err;
  549. }
  550.  
  551. OSStatus RemoveDriveQueueElement( void )
  552. {
  553.     DriveQRecPtr    theDriveQRec;
  554.  
  555.     if( gPostEventTimer != nil )
  556.     {
  557.         AbsoluteTime    timeLeft;
  558.         
  559.         // Cancel any pending timers, we don't care what the
  560.         // returned status is.
  561.         (void) CancelTimer( gPostEventTimer, &timeLeft);
  562.         gPostEventTimer = 0;
  563.     }
  564.     
  565.     driveQueueIsInstalled = false;
  566.  
  567.     theDriveQRec = GetFirstDriveQRec();                        // first volume of the drive
  568.     while (theDriveQRec)
  569.     {
  570.         EjectDrive( theDriveQRec );
  571.         theDriveQRec = GetNextDriveQRec( theDriveQRec );    // point to the next volume
  572.     }
  573.  
  574.     // if we installed a fixed/removable drive queue, remove it.
  575.     theDriveQRec = FindPermanentDriveQRec();
  576.     
  577.     if ( theDriveQRec != nil )
  578.     {
  579.         RemoveDrive( theDriveQRec );
  580.     }
  581.     
  582.     RemoveFloppyStructures();
  583.     
  584.     return noErr;
  585. }
  586.  
  587. void EjectDriveNum( UInt16 driveNum )
  588. {
  589.     DriveQRecPtr theDriveQRec;
  590.     
  591.     theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  592.     if ( theDriveQRec != nil )
  593.     {
  594.         EjectDrive( theDriveQRec );
  595.     }
  596. }
  597.  
  598. // DriveQRec management functions
  599. DriveQRecPtr    GetNewDriveQRec( void )
  600. {
  601.     int                loopCount;
  602.     DriveQRecPtr    permRec;
  603.     
  604.     permRec = FindPermanentDriveQRec();
  605.     
  606.     if ( permRec != nil )
  607.     {
  608.         if ( permRec->isValidRecord == false )
  609.         {
  610.             permRec->isValidRecord = true;
  611.             return permRec;
  612.         }
  613.     }
  614.  
  615.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  616.     {
  617.         if (( theDriveQRecArray[loopCount].isValidRecord == false ) && ( theDriveQRecArray[loopCount].isFloppy == false ))
  618.         {
  619.             theDriveQRecArray[loopCount].isValidRecord = true;
  620.             return &theDriveQRecArray[loopCount];
  621.         }
  622.     }
  623.     
  624.     return nil;
  625. }
  626.  
  627. void FreeDriveQRec( DriveQRecPtr theDriveRecPtr )
  628. {
  629.     if ( theDriveRecPtr!=nil )
  630.     {
  631.         if ( theDriveRecPtr->isFloppy == true )
  632.         {
  633.             ResetFloppyDriveQueue(theDriveRecPtr);    
  634.             theDriveRecPtr->isValidRecord = false;
  635.         }
  636.         else if ( theDriveRecPtr->isPermanentQElement == true )
  637.         {
  638.             ResetDriveQueue(theDriveRecPtr);    
  639.             theDriveRecPtr->isValidRecord = false;
  640.         }
  641.         else
  642.         {
  643.             BlockZero( theDriveRecPtr, sizeof( DriveQRec ));
  644.             theDriveRecPtr->isValidRecord = false; // this is actually done by blockZero, repeated for emphasis
  645.         }
  646.     }
  647. }
  648.  
  649. DriveQRecPtr FindDriveQRecForDriveNum( UInt16 driveNum )
  650. {
  651.     int    loopCount;
  652.     
  653.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  654.     {
  655.         if (( theDriveQRecArray[loopCount].driveNum == driveNum ) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  656.         {
  657.             return &theDriveQRecArray[loopCount];
  658.         }
  659.         
  660.         if (( theDriveQRecArray[loopCount].driveNum == driveNum ) && ( theDriveQRecArray[loopCount].isPermanentQElement == true ))
  661.         {
  662.             return &theDriveQRecArray[loopCount];
  663.         }
  664.     }
  665.     
  666.     return nil;
  667. }
  668.  
  669. DriveQRecPtr FindDriveQRecForPartitionNum( UInt32 partNum )
  670. {
  671.     int    loopCount;
  672.     
  673.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  674.     {
  675.         if (( theDriveQRecArray[loopCount].partitionNo == partNum ) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  676.         {
  677.             return &theDriveQRecArray[loopCount];
  678.         }
  679.     }
  680.     
  681.     return nil;
  682. }
  683.  
  684. DriveQRecPtr FindPermanentDriveQRec( void )
  685. {
  686.     int    loopCount;
  687.     
  688.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  689.     {
  690.         if (( theDriveQRecArray[loopCount].isPermanentQElement == true ) && ( theDriveQRecArray[loopCount].isFloppy == false ))
  691.         {
  692.             return &theDriveQRecArray[loopCount];
  693.         }
  694.     }
  695.     
  696.     return nil;
  697. }
  698.  
  699. DriveQRecPtr GetFirstDriveQRec( void )
  700. {
  701.     int    loopCount;
  702.     
  703.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  704.     {
  705.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  706.         {
  707.             return &theDriveQRecArray[loopCount];
  708.         }
  709.     }
  710.  
  711.     return nil;
  712. }
  713.  
  714. DriveQRecPtr GetNextDriveQRec( DriveQRecPtr theDriveQRec )
  715. {
  716.     int    loopCount;
  717.     int    inDriveQNum;
  718.     
  719.     for ( inDriveQNum = 0; inDriveQNum < kNumberOfDriveRecords; inDriveQNum++)
  720.     {
  721.         if ( &theDriveQRecArray[inDriveQNum] == theDriveQRec )
  722.         {
  723.             break;
  724.         }
  725.     }
  726.  
  727.     if ( inDriveQNum < kNumberOfDriveRecords )
  728.     {
  729.         for ( loopCount = inDriveQNum; loopCount < kNumberOfDriveRecords; loopCount++)
  730.         {
  731.             if ((loopCount != inDriveQNum) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  732.             {
  733.                 return &theDriveQRecArray[loopCount];
  734.             }
  735.         }
  736.     }
  737.  
  738.     return nil;
  739. }
  740.  
  741. //------------------------------------------------------------------------------
  742. //    Function:        CreateDriveQRecForPartition
  743. //
  744. //    Description:    This function creates a volume record for the specified drive.
  745. //                        The volume is appended to the drive's volume queue and a logical
  746. //                        logical drive is installed in the system drive queue.
  747. //                    
  748. //    Input:            drive:            pointer to the drive record of the volume to create
  749. //                    partitionID:    the volume's partition ID
  750. //                    volSize:        size of the volume in blocks
  751. //                    volOffset:        block offset of volume on drive
  752. //
  753. //    Output:            Returns nil pointer if fails, else pointer to volume record
  754. //
  755. //    NOTE:            Assumes all inputs are valid!
  756. //-------------------------------------------------------------------------------
  757. DriveQRecPtr CreateDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset )
  758. {
  759.     DriveQRecPtr        driveRec;
  760.     UInt32                currentCapacity, currentBlockSize;
  761.     Boolean                isWriteProtected;
  762.     OSType                currentType;     
  763.     
  764.     GetMediaProperties( ¤tCapacity,  ¤tBlockSize, &isWriteProtected, ¤tType); 
  765.     
  766.     if ( currentType == kdgFloppyType )
  767.     {
  768.         driveRec = GetFloppyDriveRec();
  769.     }
  770.     else
  771.     {
  772.         // Search for a DriveQRec record for the partition to be created…
  773.         driveRec = FindDriveQRecForPartitionNum( partitionID );
  774.     }
  775.     
  776.     if ( driveRec != nil )                                            // if record exists for this partition…
  777.     {
  778.         if (driveRec->driveStatus.diskInPlace)                        // if partition is already online…
  779.         {                                                            // we shouldn't be here - fall thru
  780.             return nil;
  781.         }
  782.     }
  783.     else                                                            // need to create DriveQRec
  784.     {
  785.         driveRec = GetNewDriveQRec();                                // Allocate storage for record
  786.     }
  787.     
  788.     if (driveRec)                                                    // If a DriveQRec was created.
  789.     {
  790.  
  791.         driveRec->isValidRecord = true;
  792.  
  793.         driveRec->isWriteProtected = isWriteProtected;
  794.         
  795.         if( driveRec->isWriteProtected == true)
  796.         {
  797.             driveRec->driveStatus.writeProt     = 0x80;                // disk is write protected
  798.         }
  799.         else
  800.         {
  801.             driveRec->driveStatus.writeProt     = 0;                // not write protected yet
  802.         }
  803.  
  804.         if ( currentType == kdgDiskType )
  805.         {
  806.             // This disk is non-ejectable
  807.             driveRec->driveStatus.diskInPlace     = 0x48;                // Non-Ejectable Disk, but we want eject calls
  808.         }
  809.         else
  810.         {
  811.             // This is a removable disk
  812.             driveRec->driveStatus.diskInPlace     = 1;                // Ejectable Disk
  813.         }
  814.  
  815.         driveRec->driveStatus.installed     = 1;                    // drive is installed
  816.         driveRec->driveStatus.dQFSID         = 0;                    // File Manager's volume type
  817.  
  818.         if( driveRec->isFloppy == false)
  819.         {
  820.             driveRec->driveStatus.qType         = 1;                            // both dQDrvSz and dQDrvSz2 are used
  821.             driveRec->driveStatus.driveSize        = (UInt16) partitionSize;        // partition size in blocks
  822.             driveRec->driveStatus.driveS1         = (UInt16) (partitionSize >> 16);
  823.         }
  824.  
  825.         driveRec->mountPartition =        false;                                // don't mount this volume,
  826.         driveRec->diskInsertPosted =    false;                                // it's not mounted yet,
  827.         driveRec->partitionNo =            partitionID;                        // save the partition ID
  828.  
  829.         // Save volume's block offset and set its access mode by setting curoffset to the
  830.         // same (access is relative to partition offset if curoffset is non-zero, else physical)
  831.         driveRec->curoffset     = partitionOffset;                        // block offset of partition
  832.         driveRec->partoffset     = partitionOffset;                        // partition offset
  833.         driveRec->partblks         = partitionSize;                        // save size for our use also
  834.         driveRec->blockSize     = currentBlockSize;
  835.         if ( currentBlockSize == kFileSystemRequestBlockSize )
  836.         {
  837.             // Blocksize is the same as the file system default
  838.             driveRec->capacity         = currentCapacity;
  839.         }
  840.         else
  841.         {
  842.             // Blocksize is not the same as the file system default,
  843.             // modify the capcity to reflect the number of file system blocks
  844.             driveRec->capacity         = currentCapacity * ( currentBlockSize / kFileSystemRequestBlockSize );
  845.         }
  846.  
  847.         // Save the media type in the DriveQRec
  848.         driveRec->deviceType = currentType;
  849.  
  850.         driveRec->mediaIconPtr = (Ptr) GetOneBitIconPtr( driveRec->deviceType );
  851.     }
  852.     
  853.     return(driveRec);
  854. }
  855.  
  856.  
  857. //------------------------------------------------------------------------------
  858. //    Function:        ScanMediaForPartitions
  859. //    Description:    Searches for partitions on the media and installs them as
  860. //                    volumes for the associated drive.  Assumes the drive does
  861. //                    not have any volumes installed yet. 
  862. //
  863. //    Input:            theDrive:    pointer to drive record
  864. //                    mountVols:    true means to mount the drive's partitions
  865. //
  866. //-------------------------------------------------------------------------------
  867. void ScanMediaForPartitions( UInt32 userData, OSStatus status )
  868. {
  869.     Boolean            timetoMountThePartitions = false;
  870.     InstallPBPtr     installPBPtr;
  871.     Boolean         weHaveAFloppy = false;
  872.     
  873.     installPBPtr = (InstallPBPtr) userData;
  874.     installPBPtr->status = status;
  875.     
  876.     switch(installPBPtr->currentState)
  877.     {
  878.         case kInstallStartState:
  879.         {
  880.             if ( theInstallPB.currentMediaType == kdgFloppyType )
  881.             {
  882.                 // If we have a floppy disk, no need to scan for partitions
  883.                 // go ahead and mount the whole disk as a volume.
  884.                 // This also allows for unformatted media to be formatted.
  885.                 weHaveAFloppy = true;
  886.                 timetoMountThePartitions = true;
  887.                 break;
  888.             }
  889.  
  890.             installPBPtr->currentState = kInstallPartitionReadDoneState;
  891.             
  892.             // Read block 0
  893.             installPBPtr->status = DoReadWritePhysicalBlocks (    (UInt32) installPBPtr, 0, 1, installPBPtr->blockSize, true,
  894.                                                             (Ptr) installPBPtr->buffer, (kFileSystemRequestBlockSize), false, &ScanMediaForPartitions );
  895.         }
  896.         break;
  897.         
  898.         case kInstallPartitionReadDoneState:
  899.         {
  900.             UInt8            *buf = (UInt8 *) &installPBPtr->buffer;            // Share 512 byte storage with PMap
  901.             Boolean            checkMacPartitions = true;
  902.             
  903.             if (installPBPtr->status == noErr)
  904.             {
  905.                 Block0        *blkZero;
  906.                 
  907.                 blkZero = (Block0 *) buf;
  908.                 
  909.                 // Check for Macintosh partitions if Block0 has the correct signature.
  910.                 checkMacPartitions = ( blkZero->sbSig == sbSIGWord );
  911.                 
  912.                 // -----  PC-Exchange DOS format bug fix  ------
  913.                 // PCX does not erase the partition map (blocks 1-31) when reformatting HFS to 
  914.                 // DOS so we may still find a partition map.  Check for DOS signature in block 0,
  915.                 // and if there, the Macintosh partition map is invalid. 
  916.                 // check for Macintosh partitions if not a DOS signature
  917. /*                checkMacPartitions = !(buf[kDOSSigLow] == kDOSSigValLo && buf[kDOSSigHi] == kDOSSigValHi);*/
  918.             }
  919.             else
  920.             {
  921.                 // An error occurred on the read, return back a failure to the client
  922.                 installPBPtr->status = ioErr;
  923.                 break;
  924.             }
  925.             
  926.             if (checkMacPartitions == false)                // we don't need to check for Macintosh parititions…
  927.             {
  928.                 timetoMountThePartitions = true;            // we found a DOS signature, try to mount as DOS
  929.                 break;
  930.             }
  931.             
  932.             installPBPtr->lastPartBlock = 1;                // assume no partition map will be found
  933.             installPBPtr->currentPartBlock = 1;
  934.  
  935.         }                                                    // no break, we want to execute next case
  936.         
  937.         case kInstallReadNextPartBlock:
  938.         {            
  939.             if ( installPBPtr->currentPartBlock <= installPBPtr->lastPartBlock )
  940.             {
  941.                 UInt32        blockSizeForRead;
  942.                 Boolean        convertToSystemBlocks;
  943.                 
  944.                 if ( installPBPtr->useNativeBlocks == true )
  945.                 {
  946.                     blockSizeForRead = installPBPtr->blockSize;
  947.                     convertToSystemBlocks = false;
  948.                 }
  949.                 else
  950.                 {
  951.                     blockSizeForRead = kFileSystemRequestBlockSize;
  952.                     convertToSystemBlocks = true;
  953.                 }
  954.                 
  955.                 // Read a block from the media…
  956.                 installPBPtr->currentState = kInstallProcessNextPartBlock;
  957.                 installPBPtr->status = DoReadWritePhysicalBlocks (    (UInt32) installPBPtr, installPBPtr->currentPartBlock, 1, installPBPtr->blockSize, convertToSystemBlocks,
  958.                                             (Ptr) installPBPtr->buffer, blockSizeForRead, false, &ScanMediaForPartitions );
  959.             }
  960.             else
  961.             {
  962.                 timetoMountThePartitions = true;            // we have finished scanning the partition map, mount what we have found
  963.             }
  964.         }
  965.         break;
  966.         
  967.         case kInstallProcessNextPartBlock:
  968.         {
  969.             Partition    *PartMap = (Partition *) &installPBPtr->buffer;
  970.             Boolean        mountPartition;
  971.             
  972.             if ( installPBPtr->status != noErr )
  973.             {
  974.                 installPBPtr->currentPartBlock += 1;
  975.                 installPBPtr->currentState = kInstallReadNextPartBlock;
  976.                 ScanMediaForPartitions( (UInt32) installPBPtr, noErr );
  977.                 return;
  978.             }
  979.     
  980.             // Verify we read a partition map entry…
  981.             if (PartMap->pmSig != newPMSigWord)         // Partition map signature?
  982.             {
  983.                 if (( installPBPtr->currentPartBlock == 1 ) && ( installPBPtr->blockSize != kFileSystemRequestBlockSize ))
  984.                 {
  985.                     // If there is not a valid Partition Map signature and the
  986.                     // drive has blocks other than the standard 512 byte blocks,
  987.                     // the partition map may be written on native blocks.
  988.                     installPBPtr->useNativeBlocks = true;
  989.                 }
  990.                 else
  991.                 {
  992.                     installPBPtr->currentPartBlock += 1;
  993.                 }
  994.                 
  995.                 installPBPtr->currentState = kInstallReadNextPartBlock;
  996.                 ScanMediaForPartitions( (UInt32) installPBPtr, noErr );
  997.                 return;
  998.             }
  999.     
  1000.             if (installPBPtr->lastPartBlock == 1)                         // Readjust the number of map blocks
  1001.                 installPBPtr->lastPartBlock = PartMap->pmMapBlkCnt;
  1002.     
  1003.             // Determine the partition type and do what is needed…
  1004.             mountPartition = ShouldPartitionBeMounted( PartMap );
  1005.             if ( mountPartition == true )
  1006.             {
  1007.                 DriveQRecPtr    newDriveRec;
  1008.                 UInt32            blockCnt;
  1009.                 UInt8            blockMultiplier = 1;
  1010.                 
  1011.                 // LaCie hard drive fix                    
  1012.                 if ( PartMap->pmDataCnt == 0)
  1013.                 {
  1014.                     blockCnt = PartMap->pmPartBlkCnt;
  1015.                 }
  1016.                 else
  1017.                 {
  1018.                     blockCnt = PartMap->pmDataCnt;
  1019.                 }
  1020.                 
  1021.                 if ( installPBPtr->useNativeBlocks == true )
  1022.                 {
  1023.                     blockMultiplier = (installPBPtr->blockSize)/kFileSystemRequestBlockSize;
  1024.                 }
  1025.  
  1026.                 // A valid paritition found!  Create a DriveQRec for it.
  1027.                 newDriveRec = CreateDriveQRecForPartition( installPBPtr->currentPartBlock * blockMultiplier, blockCnt * blockMultiplier,
  1028.                                     ( PartMap->pmPyPartStart * blockMultiplier) + ( PartMap->pmLgDataStart * blockMultiplier) );
  1029.  
  1030.                 if ( newDriveRec == nil )                // If we failed, try the next partition
  1031.                 {
  1032.                     break;
  1033.                 }
  1034.  
  1035.                 // Save this partition's map entry number (remember to subtract 1 since the partition map starts on block 1)
  1036.                 newDriveRec->partMapEntryNum = installPBPtr->currentPartBlock-1;
  1037.             
  1038.                 // Determine if the old or new bits should be used
  1039.                 if ( *((UInt32 *) &PartMap->pmPad[0x50]) == kPMapDriveSetupSig )
  1040.                 {
  1041.                     // This Partition Map has the DriveSetup signature, check the old bits
  1042.                     // Check if the partition is software write protected.  
  1043.                     if ((PartMap->pmPartStatus & STAT_WRITABLE) == STAT_WRITABLE)
  1044.                     {
  1045.                         // Only change the value in the drive queue element if it is write protected since if the media 
  1046.                         // is hardware write protected, the locked flag in the drive queue element will already reflect this.                
  1047.                         newDriveRec->writeProtectedPart     = false;
  1048.                     }
  1049.                     else
  1050.                     {
  1051.                         // This partition is not marked as writeable so the locked flag in the 
  1052.                         // drive queue needs to be set so that the OS won't try to write.
  1053.                         newDriveRec->writeProtectedPart     = true;
  1054.                         newDriveRec->driveStatus.writeProt     = 0x80;
  1055.                     }
  1056.     
  1057.                     if (( PartMap->pmPartStatus & STAT_MOUNT ) == STAT_MOUNT)
  1058.                     {    
  1059.                         // This partition should be mounted, set the flag so we will post a disk insert event
  1060.                         newDriveRec->mountPartition = true;
  1061.                     }
  1062.                     else
  1063.                     {
  1064.                         // Since we do not support the Drive Setup call to mount partitions,
  1065.                         // for now, we will just remove the DriveQRec from the list.
  1066.                         FreeDriveQRec( newDriveRec );
  1067.                     }
  1068.                 }
  1069.                 else
  1070.                 {
  1071.                     // Check if the partition is software write protected.  
  1072.                     if ((PartMap->pmPartStatus & kPartitionHFSIsWriteProtected) == kPartitionHFSIsWriteProtected)
  1073.                     {
  1074.                         // This partition is not marked as writeable so the locked flag in the 
  1075.                         // drive queue needs to be set so that the OS won't try to write.
  1076.                         newDriveRec->writeProtectedPart     = true;
  1077.                         newDriveRec->driveStatus.writeProt     = 0x80;
  1078.                     }
  1079.                     else
  1080.                     {
  1081.                         // Only change the value in the drive queue element if it is write protected since if the media 
  1082.                         // is hardware write protected, the locked flag in the drive queue element will already reflect this.                
  1083.                         newDriveRec->writeProtectedPart     = false;
  1084.                     }
  1085.     
  1086.                     if (( PartMap->pmPartStatus & kPartitionHFSDoNotAutomount ) != kPartitionHFSDoNotAutomount)
  1087.                     {    
  1088.                         // This partition should be mounted, set the flag so we will post a disk insert event
  1089.                         newDriveRec->mountPartition = true;
  1090.                     }
  1091.                     else
  1092.                     {
  1093.                         // Since we do not support the Drive Setup call to mount partitions,
  1094.                         // for now, we will just remove the DriveQRec from the list.
  1095.                         FreeDriveQRec( newDriveRec );
  1096.                     }
  1097.                 }
  1098.  
  1099. /*                if ((PartMap->pmPartStatus & kPartitionHFSIsStartup) == kPartitionHFSIsStartup)        // is this flagged as the boot partition?*/
  1100. /*                {*/
  1101. /*                    newDriveRec->startupPartition = true;*/
  1102. /*                }*/
  1103. /*                else*/
  1104. /*                {*/
  1105. /*                    newDriveRec->startupPartition = false;*/
  1106. /*                }*/
  1107.             }
  1108.  
  1109.             // Go to next Partition        
  1110.             installPBPtr->currentPartBlock += 1;
  1111.             installPBPtr->currentState = kInstallReadNextPartBlock;
  1112.             
  1113.             ScanMediaForPartitions( (UInt32) installPBPtr, installPBPtr->status );
  1114.             return;
  1115.         }
  1116.         break;
  1117.     }
  1118.  
  1119.     if ( timetoMountThePartitions == true )
  1120.     {
  1121.         DriveQRecPtr    theDriveQRec;
  1122.         
  1123.         // If no partitions were found from the search above we assume the following:
  1124.         //      1. A Macintosh partition map exists, but it has either no file system partitions
  1125.         //        or no partitions which we recognize (either or which is unlikely).
  1126.         //     2.    The media has a Macintosh floppy format (HFS with no partition map)
  1127.         //     3.    The media has a foreign format (DOS, etc.).
  1128.         //
  1129.         // In all cases we create a volume of the entire media capacity, post a disk inserted
  1130.         // event and let the File System Manager try and figure it out.  Note we post a disk
  1131.         // inserted event rather than notifying FSM so if the media is not recognized (because
  1132.         // it's unformatted or the correct file system is not installed) the system will prompt
  1133.         // with a "This is not a Macintosh disk…" message.  If we call FSM instead, the user will
  1134.         // not be prompted when the media is unformatted.  This provides a way to format media
  1135.         // and also allows us to eject PCMCIA drives which have no volumes (no icons on desktop).
  1136.                 
  1137.         if ( GetNumberOfVolumes() == 0)            // if no partitions were found…
  1138.         {
  1139.             // Create a volume of entire media capacity with partitionID of 1
  1140.             if ( installPBPtr->blockSize == kFileSystemRequestBlockSize)
  1141.             {
  1142.                 theDriveQRec = CreateDriveQRecForPartition( 1, installPBPtr->capacity, 0 );
  1143.             }
  1144.             else
  1145.             {
  1146.                 UInt32     FSBlocksPerDeviceBlocks;
  1147.                 
  1148.                 FSBlocksPerDeviceBlocks = installPBPtr->blockSize/kFileSystemRequestBlockSize;
  1149.                 
  1150.                 theDriveQRec = CreateDriveQRecForPartition( 1, (installPBPtr->capacity * FSBlocksPerDeviceBlocks), 0 );
  1151.             }
  1152.  
  1153.             if(theDriveQRec)
  1154.             {
  1155.                 theDriveQRec->mountPartition = true;                    // post disk inserted event later
  1156.             }
  1157.         }
  1158.  
  1159.         // DriveQRecs have been created for all partitions, now install them into the Drive Queue and 
  1160.         // let them system know about them by posting Disk Insert events.
  1161.         if ( weHaveAFloppy == true )
  1162.         {
  1163.             if    (theDriveQRec->mountPartition == true)            // Do not do Add Drive for partitions not to be mounted
  1164.             {
  1165.                 theDriveQRec->inDriveQ = true;                    // mark this entry as having been added to the drive Q.
  1166.             }
  1167.         }
  1168.         else
  1169.         {
  1170.             // Add the remaining volumes to the drive queue…
  1171.             theDriveQRec = GetFirstDriveQRec();            // first DriveQRec
  1172.             while (theDriveQRec)
  1173.             {
  1174.                 if    (theDriveQRec->mountPartition == true)        // Do not do Add Drive for partitions not to be mounted
  1175.                 {
  1176.                     if (theDriveQRec == FindPermanentDriveQRec())
  1177.                     {
  1178.                         //theDriveQRec->driveNum = (FindPermanentDriveQRec())->driveNum;    // assign a logical drive number
  1179.                     }
  1180.                     else
  1181.                     {
  1182.                         theDriveQRec->driveNum = NextQDrive();        // assign a logical drive number
  1183.                         NativeAddDrive(gOurDrvrRefNum, theDriveQRec->driveNum, (DrvQElPtr) &theDriveQRec->driveStatus.qLink);
  1184.                     }
  1185.                     
  1186.                     theDriveQRec->inDriveQ = true;                    // mark this entry as having been added to the drive Q.
  1187.                 }
  1188.                 
  1189.                 theDriveQRec = GetNextDriveQRec( theDriveQRec );                // point to the next volume
  1190.             }
  1191.         }
  1192.  
  1193.         if ( GetNumberOfVolumes() != 0 )
  1194.         {
  1195.             OSErr theErr;
  1196.  
  1197.             theErr = PostTheDiskInsertEvents();
  1198.             if(theErr != noErr)
  1199.             {
  1200.                 // For some reason, the disk could not be mounted,
  1201.                 // We should eject and let the user decide whether to try again.
  1202.                 (*installPBPtr->installCompletion)( false );
  1203.                 return;
  1204.             }
  1205.         }
  1206.         else                                                    // Abort if no volumes installed for drive        
  1207.         {
  1208.             (*installPBPtr->installCompletion)( false );
  1209.             return;
  1210.         }
  1211.     
  1212.         (*installPBPtr->installCompletion)( true );
  1213.         return;
  1214.     }
  1215.     
  1216.     if ((installPBPtr->status != 1 ) && (installPBPtr->status != noErr))
  1217.     {
  1218.         (*installPBPtr->installCompletion)( false );
  1219.     }
  1220. }
  1221.  
  1222. DriveQRecPtr CreateNewDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset )
  1223. {
  1224.     DriveQRecPtr    driveRec = nil;        // pointer to our volume record structure
  1225.     
  1226.     driveRec = CreateDriveQRecForPartition( partitionID, partitionSize, partitionOffset );
  1227.     if ( driveRec ) 
  1228.     {
  1229.         driveRec->driveNum = NextQDrive();        // assign a logical drive number
  1230.         NativeAddDrive( gOurDrvrRefNum, driveRec->driveNum,(DrvQElPtr)  &driveRec->driveStatus.qLink);
  1231.         driveRec->inDriveQ = true;
  1232.         
  1233.         return driveRec;
  1234.     }
  1235.     
  1236.     return driveRec;
  1237. }
  1238.  
  1239. //------------------------------------------------------------------------------
  1240. //    Function:        InstallDrive
  1241. //
  1242. //    Description:    Installs a physical drive and its volumes under the driver's
  1243. //                    control.  The driver determines if the drive is one it can
  1244. //                    manage, and if so, creates and initializes the drive's record,
  1245. //                    sets the drives operating mode and options, and mounts its
  1246. //                    partitions to the system.
  1247. //
  1248. //-------------------------------------------------------------------------------
  1249. void InstallDrive( DriveInstallCompletionProcPtr completionProc )
  1250. {
  1251.     //..............................................................................
  1252.     // Search for file system partitions on the media and install them as volumes
  1253.     // of this drive.  If no volumes, the drive must be considered unusable.
  1254.     UInt32    currentCapacity, currentBlockSize;
  1255.     Boolean    isWriteProtected;
  1256.     OSType    currentType;
  1257.     
  1258.     GetMediaProperties( ¤tCapacity,  ¤tBlockSize, &isWriteProtected, ¤tType ); 
  1259.  
  1260.     BlockZero((Ptr) &theInstallPB, sizeof(InstallPB));
  1261.     theInstallPB.capacity = currentCapacity;
  1262.     theInstallPB.blockSize = currentBlockSize;
  1263.     theInstallPB.currentMediaType = currentType;
  1264.     theInstallPB.installCompletion = completionProc;
  1265.     theInstallPB.useNativeBlocks = false;
  1266.     theInstallPB.currentState = kInstallStartState;
  1267.     ScanMediaForPartitions( (UInt32) &theInstallPB, noErr );
  1268. }
  1269.  
  1270.  
  1271. //------------------------------------------------------------------------------
  1272. //    Function:        EjectDrive
  1273. //    Description:    Removes a physical drive and its volumes from our control
  1274. //                    
  1275. //-------------------------------------------------------------------------------
  1276. void EjectDrive(DriveQRecPtr theDrivePtr)
  1277. {        
  1278.     if (theDrivePtr)                                // If the drive exists…
  1279.     {
  1280.         if( theDrivePtr->isPermanentQElement == false )
  1281.         {
  1282.             Dequeue((QElemPtr) &(theDrivePtr->driveStatus.qLink), GetDrvQHdr());    // remove from drive queue
  1283.         }
  1284.         
  1285.         FreeDriveQRec( theDrivePtr );
  1286.     }
  1287. }
  1288.  
  1289. //------------------------------------------------------------------------------
  1290. //    Function:        RemoveDrive
  1291. //    Description:    This is used to remove any Drive Queue element
  1292. //                    this includes our permanent queue element. 
  1293. //                    
  1294. //-------------------------------------------------------------------------------
  1295. void RemoveDrive(DriveQRecPtr theDrivePtr)
  1296. {        
  1297.     if (theDrivePtr)                                // If the drive exists…
  1298.     {
  1299.         Dequeue((QElemPtr) &(theDrivePtr->driveStatus.qLink), GetDrvQHdr());    // remove from drive queue        
  1300.     }
  1301.     
  1302.     FreeDriveQRec( theDrivePtr );
  1303. }
  1304.  
  1305. //------------------------------------------------------------------------------
  1306. //    Function:        IsDriveQueue1Free()
  1307. //
  1308. //    Description:    Returns true if drive queue element one is not in use,
  1309. //                    and returns false if it is.
  1310. //                    
  1311. //    Input:            none
  1312. //
  1313. //    Output:            Boolean
  1314. //-------------------------------------------------------------------------------
  1315. Boolean IsDriveQueueNumberFree( UInt16 driveNum )
  1316. {
  1317.     QHdrPtr    qhdr = GetDrvQHdr();                // Pointer to Drive Queue 
  1318.     DrvQEl    *qel = (DrvQEl*) (qhdr->qHead);        // Pointer to first element 
  1319.  
  1320.     while (qel)                                 // While not end of queue, 
  1321.     {
  1322.         if (qel->dQDrive == driveNum)             // check to see if drive number is in use 
  1323.         {
  1324.             return false;                        // drive number is in use, stop looking
  1325.         }
  1326.         else                                    // else next queue element
  1327.         {
  1328.             qel = (DrvQEl*) (qel->qLink);
  1329.         }
  1330.     }
  1331.  
  1332.     return true;                                // if we got here, drive number is free
  1333. }
  1334.  
  1335. //------------------------------------------------------------------------------
  1336. //    Function:        NextQDrive
  1337. //
  1338. //    Description:    Returns the next unused logical drive number from the system 
  1339. //                    Drive Queue.  The Drive Queue is searched starting with a
  1340. //                    logical drive number 8.
  1341. //                    
  1342. //    Input:            none
  1343. //
  1344. //    Output:            The highest Drive Queue drive number + 1
  1345. //-------------------------------------------------------------------------------
  1346. SInt16 NextQDrive( void )
  1347. {
  1348.     QHdrPtr    qhdr = GetDrvQHdr();                // Pointer to Drive Queue 
  1349.     DrvQEl    *qel = (DrvQEl*) (qhdr->qHead);        // Pointer to first element 
  1350.     SInt16    drv = 8;                            // Start above built in drives 
  1351.  
  1352.     while (qel)                                 // While not end of queue, 
  1353.     {
  1354.         if (qel->dQDrive == drv)                 // if drive number used, 
  1355.         {
  1356.             drv++;                                // bump number, and 
  1357.             qel = (DrvQEl*) (qhdr->qHead);        // search from start 
  1358.         }
  1359.         else                                    // else next queue element 
  1360.         {
  1361.             qel = (DrvQEl*) (qel->qLink);
  1362.         }
  1363.     }
  1364.  
  1365.     return drv;                                    // Return the next logical drive 
  1366. }
  1367.  
  1368. //------------------------------------------------------------------------------
  1369. //    Function:        UpdateQ
  1370. //    Description:    Updates the specified drive in the system drive queue with
  1371. //                    the specified capacity
  1372. //                    
  1373. //    Input:            qDrive:        the drive to update
  1374. //                    newSize:    the new drive capacity
  1375. //-------------------------------------------------------------------------------
  1376. void UpdateQ(SInt16 qDrive, SInt32 newSize)
  1377. {
  1378.     DriveQRecPtr    theDriveQ; 
  1379.     
  1380.     theDriveQ = FindDriveQRecForDriveNum( qDrive );
  1381.     if ( theDriveQ != nil )
  1382.     {
  1383.         DrvQEl *qel;
  1384.         
  1385.         qel = (DrvQEl *) &(theDriveQ->driveStatus.qLink);
  1386.         qel->dQDrvSz2         = newSize>>16;            // new capacity (hi word)
  1387.         qel->dQDrvSz         = newSize;                // low word of capacity 
  1388.         theDriveQ->partblks = newSize;                // save size for our use also
  1389.     }
  1390. }
  1391.  
  1392. //------------------------------------------------------------------------------
  1393. //    FUNCTION:    NextPartitionID
  1394. //    PURPOSE:    Returns the next unique partition ID for all volumes associated
  1395. //                with the specified drive.  NOTE: This function should be used only
  1396. //                when adding volumes which do not have a partition map on the media.
  1397. //                
  1398. //    INPUT:        drive:    pointer to the drive record to search for next partition ID
  1399. //
  1400. //    OUTPUT:        a unique partition ID related to the specified volume
  1401. //
  1402. //-------------------------------------------------------------------------------
  1403. SInt32 NextPartitionID( void )
  1404. {
  1405.     DriveQRecPtr     driveQ = nil;
  1406.     SInt32             nextPartitionID = 1;                // Start search with partition ID of 1
  1407.  
  1408.     driveQ = GetFirstDriveQRec();                        // first DriveQRec pointer
  1409.  
  1410.     while (driveQ)                                        // while not end of DriveQRec queue…
  1411.     {
  1412.         if (driveQ->partitionNo == nextPartitionID)        // if partition ID used
  1413.         {
  1414.             nextPartitionID++;                            // bump partition ID
  1415.             driveQ = GetFirstDriveQRec();                // reset DriveQRec pointer
  1416.         }
  1417.         else
  1418.         {
  1419.             driveQ = GetNextDriveQRec( driveQ );        // otherwise, point to next DriveQRec
  1420.         }
  1421.     }
  1422.     
  1423.     return nextPartitionID;                                // return number of next partition
  1424. }
  1425.  
  1426. //------------------------------------------------------------------------------
  1427. //    Function:        PostTheDiskInsertEvents
  1428. //    Description:    Post Disk Insert event for all partitions to be mounted
  1429. //
  1430. //    Input:            none
  1431. //
  1432. //    Output:            Returns any errors that occur from PostEvent
  1433. //-------------------------------------------------------------------------------
  1434. OSStatus PostTheDiskInsertEvents( void )
  1435. {
  1436.     DriveQRecPtr        driveRec;
  1437.     OSStatus            mountErr = noErr;
  1438.     
  1439.     // Post a Disk Inserted event for all HFS partitions not yet mounted
  1440.     driveRec = GetFirstDriveQRec();                                // first DriveQRec structure
  1441.     
  1442.     while (driveRec)                                             // for all partitions on drive…
  1443.     {    
  1444.         if ((driveRec->driveStatus.diskInPlace != 0) &&            // if media in place,
  1445.            (driveRec->mountPartition) &&                         // and partition should be mounted,
  1446.            (!driveRec->diskInsertPosted))                        // and hasn't been done yet
  1447.         {
  1448.             // This DriveQRec is marked as mountable, check if
  1449.             // PostEvents are turned on and if so issue one for this DriveQRec.
  1450.             if ( gDoPostEvents == true )
  1451.             {
  1452.                 mountErr = PostEvent(diskEvt, driveRec->driveNum);
  1453.             }
  1454.             else
  1455.             {
  1456.                 // PostEvents are turned off, return noErr because
  1457.                 // the application that turned the PostEvents off
  1458.                 // should handle mounting the appropriate drives.
  1459.                 mountErr = noErr;
  1460.             }
  1461.             
  1462.             if ( mountErr == noErr )
  1463.             {
  1464.                 driveRec->diskInsertPosted = true;
  1465.             }
  1466.         }
  1467.  
  1468.         driveRec = GetNextDriveQRec( driveRec );                            // next DriveQRec pointer
  1469.     }
  1470.  
  1471.     if ( mountErr != noErr )
  1472.     {
  1473.         // We should only get an error to PostEvent on boot,
  1474.         // Set our timer try again
  1475.         AbsoluteTime    theWait;
  1476.         
  1477.         theWait = DurationToAbsolute(durationSecond * 60);
  1478.         theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
  1479.         mountErr = SetInterruptTimer( &theWait, &RetryPostEventInterrupt, nil, &gPostEventTimer);
  1480.     }
  1481.     
  1482.     return mountErr;                                                // return error if one occurred
  1483. }
  1484.  
  1485. OSStatus RetryPostEventInterrupt( void *p1, void *p2)
  1486. {
  1487. #pragma unused ( p1, p2 )
  1488.     gPostEventTimer = 0;
  1489.     
  1490.     (void) PostTheDiskInsertEvents();
  1491.     return noErr;
  1492. }
  1493.  
  1494. #pragma mark --
  1495. #pragma mark Volume Related Routines
  1496. //------------------------------------------------------------------------------
  1497. //    Function:        IsVolumeMountedForDrive
  1498. //    Description:    Searches the volume queue for a mounted volume specified 
  1499. //                    by vRefNum.  If one is found, true is returned.
  1500. //                    
  1501. //    Input:            driveNum:    the volume reference to search for
  1502. //
  1503. //    Output:            true if volume mounted, else false
  1504. //-------------------------------------------------------------------------------
  1505. Boolean IsVolumeMountedForDrive( UInt16 driveNum )
  1506. {
  1507.     QHdrPtr    volQ = LMGetVCBQHdr();     // VCB queue head pointer
  1508.     VCBPtr    theVol;                    // first VCB
  1509.  
  1510.     if ( volQ == nil )
  1511.     {
  1512.         theVol = nil;
  1513.     }
  1514.     else
  1515.     {
  1516.         theVol = (VCBPtr) volQ->qHead;
  1517.     }
  1518.  
  1519.     while( theVol != nil )
  1520.     {
  1521.         // The test for whether a volume is mounted or not is done using
  1522.         // the VCB fields vcbDrvNum and vcbDRefNum.  A volume is mounted
  1523.         // only if it is online.
  1524.         // 
  1525.         //                    online            offline            ejected
  1526.         // 
  1527.         //    vcbDrvNum        >0 (DrvNum)         0                 0
  1528.         //    vcbDRefNum        <0 (DRefNum)    <0 (-DrvNum)    >0 (DrvNum)
  1529.     
  1530.         if (theVol->vcbDrvNum == driveNum)    // if volume specified is online…
  1531.         {
  1532.             return true;                    // volume is mounted
  1533.         }
  1534.         
  1535.         theVol = (VCBPtr) theVol->qLink;    // next VCBPtr
  1536.     }
  1537.     
  1538.     // There is no volume mounted for the requested driveNum.
  1539.     return false;
  1540. }
  1541.  
  1542. #pragma mark --
  1543. #pragma mark Partition Format Related Routines
  1544. //------------------------------------------------------------------------------
  1545. //    Function:        ConvertToUC
  1546. //    Description:    Converts the input ASCII character to its upper if possible.
  1547. //                    Character range is a…z
  1548. //                    
  1549. //    Input:            theCharacter:    character to be converted
  1550. //    Output:            the upper case of the character if possible, else the character
  1551. //-------------------------------------------------------------------------------
  1552. static UInt8         ConvertToUC(UInt8 theCharacter);
  1553.  
  1554. UInt8 ConvertToUC(UInt8 theCharacter)
  1555. {
  1556.     if ((theCharacter >= 'a') && (theCharacter <= 'z'))    // a lower case character?
  1557.         return(theCharacter & 0xDF);    // if so, convert to upper case
  1558.     else
  1559.         return(theCharacter);            // if not, return as is
  1560. }
  1561.  
  1562. //------------------------------------------------------------------------------
  1563. //    Function:        GetPartitionType
  1564. //    Description:    This function determines the partition type.  Following parti- 
  1565. //                    tion types are recognized:  
  1566. //                    • Apple driver partition
  1567. //                    • HFS partition 
  1568. //                    • Apple partition map, Apple Free, and Apple Scratch
  1569. //                    If an unknown type is detected, the function returns ISADDTOQUEUE
  1570. //                    file system ID to be handled by someone else above.
  1571. //                    
  1572. //    Input:            A pointer to a partition: pm *
  1573. //
  1574. //    Output:            Returns true if this partion should be mounted
  1575. //
  1576. //-------------------------------------------------------------------------------
  1577. Boolean ShouldPartitionBeMounted(Partition* thePartition )
  1578. {
  1579.     SInt16 i,j;
  1580.     static char *knownPartitionTypes[] = {
  1581.         "APPLE_DRIVER43",
  1582.         "APPLE_HFS",
  1583.         "APPLE_PARTITION_MAP",
  1584.         "APPLE_FREE",
  1585.         "APPLE_SCRATCH",
  1586.         "APPLE_PRODOS",
  1587.         "APPLE_DRIVER_ATA",
  1588.         "APPLE_PATCHES",
  1589.         "APPLE_UNIX_SVR2"
  1590.     };
  1591.  
  1592.     // The following defines refer to the items in knownPartitionTypes. 
  1593. #define POS_BEGIN 0
  1594. #define POS_APPLE_DRIVER 0
  1595. #define POS_APPLE_HFS 1
  1596. #define POS_APPLE_PRODOS 5
  1597. #define    POS_APPLE_ATADRIVER    6
  1598. #define POS_END 8
  1599.  
  1600.     // First check to see if we recognize one of the known partitions. 
  1601.     for (j = POS_BEGIN; j <= POS_END; j++) 
  1602.     {
  1603.         char *knownPartitionTypePtr;
  1604.         
  1605.         i = 0;
  1606.         knownPartitionTypePtr = knownPartitionTypes[j];
  1607.         while (knownPartitionTypePtr[i] == ConvertToUC (thePartition->pmParType[i]))
  1608.         {
  1609.             if (knownPartitionTypePtr[i++] == '\0')        // We found one that we recognize. 
  1610.             {
  1611.                 switch(j) 
  1612.                 {
  1613.                     case POS_APPLE_HFS:
  1614.                     case POS_APPLE_PRODOS:
  1615.                     {
  1616.                         return true;
  1617.                     }
  1618.                     break;
  1619.     
  1620.                     default:
  1621.                     {
  1622.                         // We must have found one of the ones that can't be mounted. 
  1623.                         return false;
  1624.                     }
  1625.                     break;
  1626.                 }
  1627.             }
  1628.         }
  1629.     }
  1630.     
  1631.     // None matched.  Now see if we shouldn't add this to the queue. 
  1632.     return false;
  1633. }
  1634.